<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Controllers\ScoreRuleController;
use App\Models\ReservationApply;
use App\Models\Reservation;
use App\Models\ReservationSchedule;
use App\Models\ReservationSpecialSchedule;
use App\Models\UserInfo;
use App\Validate\ReservationApplyValidate;
use Exception;
use Illuminate\Support\Facades\DB;

/**
 * 预约记录类
 */
class ReservationApplyController extends CommonController
{
    protected $model;
    protected $scheduleModel;
    protected $reservationModel;
    protected $validate;

    protected $score_type = '5';

    public function __construct()
    {
        parent::__construct();

        $this->model = new ReservationApply();
        $this->reservationModel = new Reservation();
        $this->scheduleModel = new ReservationSchedule();
        $this->validate = new ReservationApplyValidate();
    }

    /**
     * 预约申请列表
     * @param reservation_id int 预约id
     * @param page int 页码
     * @param limit int 分页大小
     * @param keywords string 搜索关键词
     * @param start_date date 搜索开始时间
     * @param end_date date 搜索结束时间
     * @param status int 用于筛选用户列表  预约状态   1.已通过  3待审核，4已拒绝 ,5 已过期 , 6 已签到（已领取） 7 已签退 （已归还）
     * @param is_violate int 是否违规  1正常 2违规 默认1
     * @param make_way int 预约方式   1  前台自主预约  2 管理员手动预约			
     */
    public function lists()
    {
        $this->reservationModel->checkApplyStatus(); //处理逾期报名信息

        $page = $this->request->page ? intval($this->request->page) : 1;
        $limit = $this->request->limit ? $this->request->limit : 10;
        $keywords = $this->request->keywords;
        $start_date = $this->request->start_date;
        $end_date = $this->request->end_date;
        $reservation_id = $this->request->reservation_id;
        $status = $this->request->status;
        $is_violate = $this->request->is_violate;
        $make_way = $this->request->make_way;

        $reservation = $this->reservationModel->where('id', $reservation_id)->first();
        if (empty($reservation)) {
            return $this->returnApi(201, "参数传递失败");
        }

        $res = $this->model->lists($reservation_id, null, $status, $is_violate, $keywords, $start_date, $end_date, $make_way, $limit);

        if (empty($res['data'])) {
            return $this->returnApi(203, "暂无数据");
        }
        $res = $this->disPageData($res);
        $res['data'] = $this->addSerialNumber($res['data'], $page, $limit);

        return $this->returnApi(200, "查询成功", true, $res);
    }


    /**
     * 获取用户对于某个预约的预约记录
     * @param reservation_id int 预约id
     * @param user_id int 用户id
     * @param page int 页码
     * @param limit int 分页大小
     */
    public function reservationApplyHistory()
    {
        $reservation_id = $this->request->reservation_id;
        $user_id = $this->request->user_id;
        $page = $this->request->page ? intval($this->request->page) : 1;
        $limit = $this->request->limit ? $this->request->limit : 10;

        $res = $this->model->lists($reservation_id, $user_id, null, null, null, null, null, $limit);

        if (empty($res['data'])) {
            return $this->returnApi(203, "暂无数据");
        }
        $res = $this->disPageData($res);
        $res['data'] = $this->addSerialNumber($res['data'], $page, $limit);

        return $this->returnApi(200, "查询成功", true, $res);
    }

    /**
     * 审核通过 和 拒绝
     * @param id int 申请id
     * @param status int 预约状态   1.已通过  4已拒绝
     * @param reason string 拒绝理由
     */
    public function agreeAndRefused()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('check')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        if ($this->request->status == 4 && empty($this->request->reason)) {
            return $this->returnApi(201, "拒绝理由不能为空");
        }

        DB::beginTransaction();
        try {
            $res = $this->model->agreeAndRefused($this->request->id, $this->request->status, $this->request->reason);

            /*消息推送*/
            $msg = $this->request->status == 1 ? '通过' : '拒绝';
            if ($this->request->status == 1) {
                //重置过期时间
                $apply_info = $this->model->where('id', $this->request->id)->first();
                $reservation_info = Reservation::select('node', 'clock_time')->where('id', $apply_info['reservation_id'])->first();
                if ($reservation_info['node'] == 7) {
                    $expire_time = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . "+" . $reservation_info['clock_time'] . " min"));
                    $apply_info->expire_time = $expire_time;
                    $apply_info->save(); //重置过期时间
                }

                $system_id = $this->systemAdd('预约审核已' . $msg, $res->user_id, $res->account_id, 32, $this->request->id, '您的预约：【' . $res->conReservation->name . '】已' . $msg);
            } else {
                $system_id = $this->systemAdd('预约审核已' . $msg, $res->user_id, $res->account_id, 32, $this->request->id, '您的预约：【' . $res->conReservation->name . '】已' . $msg . '拒绝理由为：' . $this->request->reason);
                if (!empty($res->score)) {
                    $score_rule = new ScoreRuleController();
                    $score_msg = $score_rule->getScoreMsg($res->score);
                    $score_rule->scoreReturn($this->score_type, $res->score, $res->user_id, $res->account_id, '预约被拒绝，' . $score_msg . ' ' . abs($res->score) . ' 积分', $system_id, '预约被拒绝');
                }
            }
            DB::commit();
            return $this->returnApi(200, $msg . "成功", true);
        } catch (Exception $e) {
            DB::rollBack();
            return $this->returnApi(202, $e->getMessage());
        }
    }


    /**
     * 预约违规 与 取消违规操作
     * @param id int 申请id
     * @param reason string 违规原因
     */
    public function violateAndCancel()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('violate_and_cancel')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }

        // 启动事务
        DB::beginTransaction();
        try {
            $res = $this->model->violateAndCancel($this->request->id, $this->request->reason);

            /*消息推送*/
            if ($res->is_violate == 2) {
                $system_id = $this->systemAdd('预约已违规', $res->user_id, $res->account_id, 33, $res->id, '您申请的预约：【' . $res->conReservation->name . '】已违规，违规理由为：' . $this->request->reason);

                // if (!empty($res->score)) {
                //     $score_rule = new ScoreRuleController();
                //     $score_msg = $score_rule->getScoreMsg($res->score);
                //     $score_rule->scoreReturn($this->score_type, $res->score,$res->user_id, $res->account_id, '预约已违规，' . $score_msg . ' ' . abs($res->score) . ' 积分', $system_id);
                // }
            } else {
                $system_id = $this->systemAdd('预约已取消违规', $res->user_id, $res->account_id, 33, $res->id, '您申请的预约：【' . $res->conReservation->name . '】已取消违规');

                // if (!empty($res->score)) {
                //     $score_rule = new ScoreRuleController();
                //     $score_msg = $score_rule->getScoreMsg(-$res->score); //相反积分
                //     $score_rule->scoreReturn($this->score_type, $res->score,$res->user_id, $res->account_id, '预约已违规，' . $score_msg . ' ' . abs($res->score) . ' 积分', $system_id);
                // }
            }

            // 提交事务
            DB::commit();
            return $this->returnApi(200, "操作成功", true);
        } catch (\Exception $e) {
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, $e->getMessage());
        }
    }


    /** 
     * 管理员取消预约
     * @param id string 预约申请id 多个用,隔开
     */
    public function applyCancel()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('apply_cancel')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }

        $ids = $this->request->ids;
        $ids = explode(',', $ids);
        $data = $this->model->whereIn('id', $ids)->whereIn('status', [1, 3])->get()->toArray();
        if (!$data) {
            return $this->returnApi(201, "未找到任何可取消的预约");
        }
        // 启动事务
        DB::beginTransaction();
        try {
            /*消息推送*/
            foreach ($data as $key => $val) {
                //取消预约
                $update_data['status'] = 2;
                $update_data['change_time'] = date('Y-m-d H:i:s');
                $this->model->where('id', $val['id'])->update($update_data);
                //通知用户
                $reservation_name = $this->reservationModel->where('id', $val['reservation_id'])->value('name');
                $this->reservationModel->where('id', $val['reservation_id'])->decrement('apply_number'); //减少预约数量

                $system_id = $this->systemAdd("预约申请失效：", $val['user_id'], $val['account_id'], 49, $val['id'], '您申请的预约：【' . $reservation_name . '】已被管理员取消，请重新预约');

                if (!empty($val['score'])) {
                    $scoreRuleObj = new ScoreRuleController();
                    $score_msg = $scoreRuleObj->getScoreMsg($val['score']);
                    $scoreRuleObj->scoreReturn($this->score_type, $val['score'], $val['user_id'], $val['account_id'], '取消预约，' . $score_msg . ' ' . abs($val['score']) . ' 积分', $system_id, '取消预约');
                }
            }
            // 提交事务
            DB::commit();
            return $this->returnApi(200, "操作成功", "YES");
        } catch (\Exception $e) {
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, $e->getMessage());
        }
    }

    /** 
     * 管理员操作用户打卡签到、签退
     * @param id int 预约id
     * @param apply_id int 申请记录id （与code 2选一）
     * @param type string 若值为：code   则是 二维码签到模式   则 code值必须要有
     * @param code string 二维码值或者读者证号
     */
    public function applySignIn()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('apply_sign_in')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $reservation_id = $this->request->id;
        $apply_id = $this->request->apply_id;

        $reservation_info = Reservation::where('id', $reservation_id)->where('is_play', 1)->where('is_del', 1)->first();
        if (empty($reservation_info)) {
            return $this->returnApi(201, "当前预约不存在");
        }

        if ($reservation_info['is_sign'] == 2) {
            return $this->returnApi(202, "此预约无须签到");
        }

        if ($this->request->type == 'code') {
            $code = $this->request->code;
            if (empty($code)) {
                return $this->returnApi(202, "请先扫描二维码");
            }
            $code_data = $this->dataDecrypt($code);
            if (empty($code_data) || empty($code_data['node']) || empty($code_data['apply_id']) || empty($code_data['expire_time']) || $code_data['node'] != 'reservation') {
                return $this->returnApi(202, "无效二维码");
            }
            if ($code_data['expire_time'] < date('Y-m-d H:i:s')) {
                return $this->returnApi(202, "二维码已过期");
            }
            $apply_id = $code_data['apply_id'];
        }

        if (empty($apply_id)) {
            return $this->returnApi(201, "参数错误");
        }
        $reservation_apply = $this->model->where('id', $apply_id)->where('reservation_id', $reservation_id)->first();
        if (!$reservation_apply) {
            return $this->returnApi(201, "参数传递错误");
        }
        if ($reservation_apply->status != 6 && $reservation_apply->status != 1) {
            return $this->returnApi(201, "当前状态无法进行操作");
        }
        if ($reservation_apply->status == 1 && date('Y-m-d H:i:s') > $reservation_apply->expire_time) {
            return $this->returnApi(201, "已超过开始打卡时间，不能打卡");
        }
        if ($reservation_apply->make_time != date('Y-m-d')) {
            return $this->returnApi(201, "当前日期与预约日期不一致，不能打卡");
        }


        if ($reservation_apply->status == 6) {
            // if ($reservation_info['node'] != 5 && $reservation_info['node'] != 6) {
            //     return $this->returnApi(201, "预约状态有误，不能签到！");
            // }
            //3分钟内不能直接签退
            if ($reservation_apply->sign_time > date('Y-m-d H:i:s', strtotime("-3 min"))) {
                return $this->returnApi(202, "您已签到，请勿重复签到，如需签退，请3分钟后在试！");
            }
        }

        if ($reservation_apply->status == 1) {
            $schedule_type = $reservation_apply->schedule_type;
            /**检查是否在排班时间内 */
            $scheduleModel = $schedule_type == 2 ? new ReservationSpecialSchedule() : new  ReservationSchedule();
            $schedule = $scheduleModel->where('id', $reservation_apply->schedule_id)->where('is_del', 1)->first();
            if (!$schedule) {
                return $this->returnApi(202, "当前时间段，未查询到任何预约排班信息");
            }
            if ($schedule->start_time > date('H:i:s', strtotime("+10 min"))) {
                return $this->returnApi(202, "只能提前10分钟签到");
            }
            if ($schedule->end_time < date('H:i:s', strtotime("-10 min"))) {
                return $this->returnApi(202, "签到时间已过，不能在进行签到");
            }
        }

        // 启动事务
        Db::beginTransaction();
        try {
            if ($reservation_apply->status == 1) {
                $reservation_apply->status = 6;
                $reservation_apply->sign_time = date("Y-m-d H:i:s");
                $msg = "签到成功";
            } else {
                $reservation_apply->status = 7;
                $reservation_apply->sign_end_time = date('Y-m-d H:i:s');
                $msg = "签退成功";
            }
            $reservation_apply->save();
            /*消息推送*/
            $reservation_name = $reservation_info['name'];
            $system_id = $this->systemAdd("预约" . $msg . "：", $reservation_apply->user_id,  $reservation_apply->account_id, 48, intval($reservation_apply->id), '【' . $reservation_name . '】预约' . $msg);
            // 提交事务
            DB::commit();
            return $this->returnApi(200, $msg, true);
        } catch (\Exception $e) {
            $msg = $e->getCode() == 202 ? $e->getMessage() : '操作失败';
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, $msg);
        }
    }

    /** 
     * 管理员操作用户打卡签退(弃用，改为签到同一个接口)
     * @param id int 预约id
     * @param apply_id int 申请记录id （与code 2选一）
     * @param type string 若值为：code   则是 二维码签到模式   则 code值必须要有
     * @param code string 二维码值或者读者证号
     */
    public function applySignOut()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('apply_sign_out')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $reservation_id = $this->request->id;
        $apply_id = $this->request->apply_id;

        if ($this->request->type == 'code') {
            $code = $this->request->code;
            if (empty($code)) {
                return $this->returnApi(202, "请先扫描二维码");
            }
            $code_data = $this->dataDecrypt($code);
            if (empty($code_data) || empty($code_data['node']) || empty($code_data['apply_id']) || empty($code_data['expire_time']) || $code_data['node'] != 'reservation') {
                return $this->returnApi(202, "无效二维码");
            }
            if ($code_data['expire_time'] < date('Y-m-d H:i:s')) {
                return $this->returnApi(202, "二维码已过期");
            }
            $apply_id = $code_data['apply_id'];
        }
        if (empty($apply_id)) {
            return $this->returnApi(201, "参数错误");
        }
        $reservation_apply = $this->model->where('id', $apply_id)->where('reservation_id', $reservation_id)->first();

        if (!$reservation_apply) {
            return $this->returnApi(201, "参数传递错误");
        }
        if ($reservation_apply->status != 6) {
            return $this->returnApi(201, "当前状态无法进行签退操作");
        }
        if ($reservation_apply->make_time != date('Y-m-d')) {
            return $this->returnApi(201, "签退时间已过，无需签退");
        }
        // 启动事务
        Db::beginTransaction();
        try {
            $reservation_apply->change_time = date('Y-m-d H:i:s');
            $reservation_apply->status = 7;
            $reservation_apply->sign_end_time = date('Y-m-d H:i:s');
            $reservation_apply->save();
            /*消息推送*/
            $reservation_name = $this->reservationModel->where('id', $reservation_apply->reservation_id)->value('name');
            $system_id = $this->systemAdd("预约签退成功：", $reservation_apply->user_id, $reservation_apply->account_id, 48, intval($reservation_apply->id), '【' . $reservation_name . '】预约签退成功');
            // 提交事务
            DB::commit();
            return $this->returnApi(200, "签退成功", "YES");
        } catch (\Exception $e) {
            $msg = $e->getCode() == 202 ? $e->getMessage() : '签退失败';
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, $msg);
        }
    }

    /** 
     * 管理员操作领取和归还钥匙
     * @param id int 预约id
     * @param apply_id int 申请记录id （与code 2选一）
     * @param type string 若值为：code   则是 二维码签到模式   则 code值必须要有
     * @param code string 二维码值或者读者证号
     * @param seat_id string 领取钥匙编号  领取必填
     */
    public function collectionAndReturn()
    {
        //增加验证场景进行验证
        if (!$this->validate->scene('collection_and_return')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $reservation_id = $this->request->id;
        $apply_id = $this->request->apply_id;

        $reservation_info = Reservation::where('id', $reservation_id)->where('is_play', 1)->where('is_del', 1)->first();
        if (empty($reservation_info)) {
            return $this->returnApi(201, "当前预约不存在");
        }

        if ($this->request->type == 'code') {
            $code = $this->request->code;
            if (empty($code)) {
                return $this->returnApi(202, "请先扫描二维码");
            }
            $code_data = $this->dataDecrypt($code);
            if (empty($code_data) || empty($code_data['node']) || empty($code_data['apply_id']) || empty($code_data['expire_time']) || $code_data['node'] != 'reservation') {
                return $this->returnApi(202, "无效二维码");
            }
            if ($code_data['expire_time'] < date('Y-m-d H:i:s')) {
                return $this->returnApi(202, "二维码已过期");
            }
            $apply_id = $code_data['apply_id'];
        }
        if ($this->request->seat_id && empty($apply_id)) {
            //重置预约id
            $reservation_apply = $this->model->where('seat_id', $this->request->seat_id)->where('reservation_id', $reservation_id)->whereIn('status', [1, 6])->first();
            if (empty($reservation_apply)) {
                return $this->returnApi(202, "预约信息不存在");
            }
            $apply_id = $reservation_apply['id'];
        }

        if (empty($apply_id)) {
            return $this->returnApi(201, "参数错误");
        }
        if (empty($reservation_apply)) {
            $reservation_apply = $this->model->where('id', $apply_id)->where('reservation_id', $reservation_id)->first();
        }
        if (!$reservation_apply) {
            return $this->returnApi(201, "参数传递错误");
        }
        if ($reservation_apply->status != 6 && $reservation_apply->status != 1) {
            return $this->returnApi(201, "当前状态无法进行操作");
        }
        if ($reservation_apply->status == 1 && date('Y-m-d H:i:s') > $reservation_apply->expire_time) {
            return $this->returnApi(201, "已超过领取时间，不能领取");
        }
        // if ($reservation_apply->make_time != date('Y-m-d')) {
        //     return $this->returnApi(201, "当前日期与预约日期不一致，不能打卡");
        // }
        if ($reservation_apply->status == 1 && (empty($this->request->seat_id) || !is_numeric($this->request->seat_id))) {
            return $this->returnApi(201, "领取编号ID规则不正确");
        }

        if ($reservation_apply->status == 6) {
            // if ($reservation_info['node'] != 5 && $reservation_info['node'] != 6) {
            //     return $this->returnApi(201, "预约状态有误，不能签到！");
            // }
            //3分钟内不能直接归还
            if ($reservation_apply->sign_time > date('Y-m-d H:i:s', strtotime("-3 min"))) {
                return $this->returnApi(202, "您刚领取，如需归还，请3分钟后重试！");
            }
        }

        // 启动事务
        Db::beginTransaction();
        try {
            if ($reservation_apply->status == 1) {
                $reservation_apply->seat_id = $this->request->seat_id;
                $reservation_apply->return_expire_time = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . "+" . $reservation_info['return_time'] . " hour"));
                $reservation_apply->status = 6;
                $reservation_apply->sign_time = date("Y-m-d H:i:s");
                $msg = "领取成功";
            } else {
                if ($reservation_apply->return_expire_time < date('Y-m-d H:i:s') && $reservation_apply['is_violate'] == 1) {
                    $reservation_apply->is_violate = 2; //自动违规
                    $reservation_apply->violate_reason = '逾期归还'; //自动违规
                    $reservation_apply->violate_time = $reservation_apply->return_expire_time;

                    $controllerObj = new Controller();
                    $controllerObj->systemAdd('预约已违规', $reservation_apply->user_id, $reservation_apply->account_id, 33, $reservation_apply->id, '您申请的预约：【' . $reservation_info['name'] . '】逾期归还，自动违规', $reservation_apply->return_expire_time);
                }

                $reservation_apply->status = 7;
                $reservation_apply->sign_end_time = date('Y-m-d H:i:s');
                $msg = "归还成功";
            }
            $reservation_apply->save();
            /*消息推送*/
            $reservation_name = $reservation_info['name'];
            $system_id = $this->systemAdd("预约" . $msg . "：", $reservation_apply->user_id,  $reservation_apply->account_id, 48, intval($reservation_apply->id), '【' . $reservation_name . '】预约' . $msg);
            // 提交事务
            DB::commit();
            return $this->returnApi(200, $msg, true);
        } catch (\Exception $e) {
            $msg = $e->getCode() == 202 ? $e->getMessage() : '操作失败';
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, $msg);
        }
    }
}
